#pragma once

#include "fxcc/core/graph/common/pch.h"

#include "gli/gli.hpp"

namespace fxcc
{
    namespace graph
    {
        namespace common
        {
            struct FXCC_API  ImageMipmap :public fxcc::Base
            {
                struct Desc
                {
                    std::string m_wicPath{};
                    
                    int m_wicReq{ 0 };

                    int m_wicHdr{ 0 };
      
                    bool m_WICFlipY{ false };

                    bool operator<(const Desc& other) const
                    {
                        return std::tie(m_wicPath, m_wicReq, m_wicHdr) <
                            std::tie(other.m_wicPath, other.m_wicReq, other.m_wicHdr);
                    }

                    bool operator==(const Desc& other) const
                    {
                        return std::tie(m_wicPath, m_wicReq, m_wicHdr) ==
                            std::tie(other.m_wicPath, other.m_wicReq, other.m_wicHdr);
                    }

                } m_Desc;

                float Aspect() const
                {
                    return m_WICTexture.Aspect();
                }

                struct   MipMapData
                {
                    int m_Width{ 0 };
                    int m_Height{ 0 };
                    int m_Depth{ 0 };
                    int m_Mipmaps { 1 };

                    int m_NrComponent{ 0 };
                    int m_HDR{ false };
                    std::vector<unsigned char> m_Data;
                    std::vector<float> m_Floats;

                    MipMapData() = default;

                    MipMapData(int w, int h, int nrComponent, int hdr) :m_Width(w), m_Height(h), m_NrComponent(nrComponent), m_HDR(hdr)
                    {

                    }
                    bool DrawRect(const MipMapData& sourceImage, const glm::ivec2& numSep, const glm::ivec2& pos);

                    void InitUINT8()
                    {
                        m_Data.clear();
                        m_Data.resize(Size());
                    }
                    void InitFloat()
                    {
                        m_Floats.clear();
                        m_Floats.resize(Size());
                    }
                    void InitData()
                    {
                        if (m_HDR)
                        {
                            InitFloat();
                        }
                        else
                        {
                            InitUINT8();
                        }
                    }
                    void AllocUINT8(unsigned char* source)
                    {
                        m_Data.clear();
                        int sz = Size();
                        m_Data.assign(source, source +sz );
                    }

                    void AllocFloat(float* source)
                    {
                        m_Floats.clear();
                        int sz = Size();
                        m_Floats.assign(source, source + sz);
                    }
                    int RowPitch() const
                    {
                        return NumBitOfPixel() * m_Width;
                    };
                    int NumBitOfPixel() const
                    {
                        if (m_HDR)
                        {
                            if (m_HDR == 1)
                            {
                                return 2;
                            }
                            if (m_HDR == 2)
                            {
                                return 4;
                            }
                            return 1;
                        }
                        else
                        {
                            return 1;
                        };
                    };

                    void AllocData() {
                        if (m_HDR)
                        {
                            m_Floats.resize(m_NrComponent * m_Width * m_Height);
                        }
                        else
                        {
                            m_Data.resize(m_NrComponent * m_Width * m_Height);
                        }
                    };
                    const void* GetData() const
                    {
                        if (m_HDR)
                        {
                            if (m_Floats.size())
                            {
                                return &m_Floats[0];
                            }
                        }
                        else
                        {
                            if (m_Data.size())
                            {
                                return &m_Data[0];
                            }
                        }
                       
                        return 0;
                    }
                    void* GetData2() 
                    {
                        if (m_HDR)
                        {
                            if (m_Floats.size())
                            {
                                return &m_Floats[0];
                            }
                        }
                        else
                        {
                            if (m_Data.size())
                            {
                                return &m_Data[0];
                            }
                        }

                        return 0;
                    }
                    int Size() const
                    {
                        return m_Width * m_Height * m_NrComponent;
                    }
                    int DataSize() const
                    {
                        return m_Width * m_Height * m_NrComponent * (m_HDR ? 4 : 1);
                    }

                    float Aspect() const
                    {
                        if (m_Height > 0.0f)
                        {
                            return (float)m_Width / (float)m_Height;
                        }
                        return 1.f;
                    }
                    void SaveBMP(const std::string& path)const;

                    void SaveHDR(const std::string& path)const;

                    std::string SaveImage(const std::string& pathnoSuffix)const;
                };

                MipMapData m_WICTexture;

                ImageMipmap(const MipMapData& wicTexture) :m_WICTexture(wicTexture)
                {
                    m_Available = true;
                }

                ImageMipmap();

                ImageMipmap(const Desc& desc);

                ~ImageMipmap();

                int RowPitch() const;

                int NumBitOfPixel() const;

                bool Init();

                bool InitWIC();
            };
        }
    }
}